package com.zxjbyte.yiyi.framework.common.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.zxjbyte.yiyi.framework.common.constant.Constant;
import com.zxjbyte.yiyi.framework.common.constant.StringPool;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

/**
 * jackson JSON工具类封装
 * @Author zhangxingjia
 * @Date 2023/3/1 16:41
 * @Version: 1.0
 */
@Slf4j
@UtilityClass
public class JsonUtil {


    /**
     * 将对象序列化成json字符串
     *
     * @param value javaBean
     * @return jsonString json字符串
     */
    @SneakyThrows
    public <T> String toJsonAsString(T value) {
        return getInstance().writeValueAsString(value);
    }

    /**
     * 将对象序列化成 json byte 数组
     *
     * @param object javaBean
     * @return jsonString json字符串
     */
    @SneakyThrows
    public byte[] toJsonAsBytes(Object object) {
        return getInstance().writeValueAsBytes(object);
    }

    /**
     * JSON 字符串进行压缩（去掉格式化）
     * @param jsonStr
     * @return
     */
    @SneakyThrows
    public String jsonStrCompact(String jsonStr){
        return readTree(jsonStr).toString();
    }

    /**
     * 验证是否为合法的Json字符串
     * @param jsonString
     * @return
     */
    public boolean isJsonString(String jsonString) {
        try {
            JsonNode jsonNode = readTree(jsonString);
            return jsonNode.isObject() || jsonNode.isArray();
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 简答验证是否为Json字符串
     * 开头是否为 { 或 [，结尾是否为 } 或 ]
     * 这个方法不能验证 JSON 字符串中的数据类型和格式是否正确，只能判断是否符合 JSON 格式规范
     * @param str
     * @return
     */
    public boolean isSimpleJsonString(String str) {
        if (StrUtil.isBlank(str)) {
            return false;
        }
        return str.matches("^(\\{[\\s\\S]*}|\\[[\\s\\S]*])$");
    }

    /**
     * Map对象转换为带有 @JsonTypeInfo 注解的接口的实现类
     * @param fromValue
     * @param targetType
     * @param <T>
     * @return
     */
    public <T> T mapToObjectWithTypeInfo(Map<String, Object> fromValue, Class<T> targetType) {
        return JSONUtil.toBean(JSONUtil.parseObj(fromValue), targetType);
    }

    /**
     * 将json反序列化成对象
     *
     * @param content   content
     * @param valueType Type
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(String content, Type valueType) {
        JavaType javaType = getInstance().getTypeFactory().constructType(valueType);
        return getInstance().readValue(content, javaType);
    }


    /**
     * 将json反序列化成对象
     *
     * @param content   content
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(String content, Class<T> valueType) {
        return getInstance().readValue(content, valueType);
    }

    /**
     * 将字符串解析成指定类型的对象
     * 使用 {@link #parseObject(String, Class)} 时，在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下，
     * 如果text没有 '@class' 属性，则会报错[ missing type id property '@class']。
     *
     * @param text 字符串
     * @param clazz 类型
     * @return 对象
     */
    public <T> T parseObject2(String text, Class<T> clazz) {
        if (StrUtil.isEmpty(text)) {
            return null;
        }
        return JSONUtil.toBean(text, clazz);
    }

    /**
     * 将json反序列化成对象
     *
     * @param content       content
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(String content, TypeReference<T> typeReference) {
        return getInstance().readValue(content, typeReference);
    }

    /**
     * 将json byte 数组反序列化成对象
     *
     * @param bytes     json bytes
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(byte[] bytes, Class<T> valueType) {
        return getInstance().readValue(bytes, valueType);
    }


    /**
     * 将json反序列化成对象
     *
     * @param bytes         bytes
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(byte[] bytes, TypeReference<T> typeReference) {
        return getInstance().readValue(bytes, typeReference);
    }

    /**
     * 将json反序列化成对象
     *
     * @param in        InputStream
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(InputStream in, Class<T> valueType) {
       return getInstance().readValue(in, valueType);
    }

    /**
     * 将json反序列化成对象
     *
     * @param in            InputStream
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    public <T> T parseObject(InputStream in, TypeReference<T> typeReference) {
        return getInstance().readValue(in, typeReference);
    }

    /**
     * 将json反序列化成List对象
     *
     * @param content      content
     * @param valueTypeRef class
     * @param <T>          T 泛型标记
     * @return List<T>
     */
    public <T> List<T> parseList(String content, Class<T> valueTypeRef) {
        try {
            JavaType javaType = getInstance().getTypeFactory().constructCollectionType(List.class, valueTypeRef);
            return getInstance().readValue(content, javaType);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 将json字符串转成 JsonNode
     *
     * @param jsonString jsonString
     * @return jsonString json字符串
     */
    @SneakyThrows
    public JsonNode readTree(String jsonString) {
        Objects.requireNonNull(jsonString, "jsonString is null");
        return getInstance().readTree(jsonString);

    }

    /**
     * 将json字符串转成 JsonNode
     *
     * @param in InputStream
     * @return jsonString json字符串
     */
    @SneakyThrows
    public JsonNode readTree(InputStream in) {
        Objects.requireNonNull(in, "InputStream in is null");
        return getInstance().readTree(in);
    }

    /**
     * 将json字符串转成 JsonNode
     *
     * @param content content
     * @return jsonString json字符串
     */
    @SneakyThrows
    public JsonNode readTree(byte[] content) {
        Objects.requireNonNull(content, "byte[] content is null");
        return getInstance().readTree(content);
    }

    /**
     * 将json字符串转成 JsonNode
     *
     * @param jsonParser JsonParser
     * @return jsonString json字符串
     */
    @SneakyThrows
    public JsonNode readTree(JsonParser jsonParser) {
        Objects.requireNonNull(jsonParser, "jsonParser is null");
        return getInstance().readTree(jsonParser);
    }


    /**
     * 将json byte 数组反序列化成对象
     *
     * @param content   json bytes
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable byte[] content, Class<T> valueType) {
        if (ObjectUtil.isEmpty(content)) {
            return null;
        }
        return getInstance().readValue(content, valueType);
    }

    /**
     * 将json反序列化成对象
     *
     * @param jsonString jsonString
     * @param valueType  class
     * @param <T>        T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable String jsonString, Class<T> valueType) {
        if (StrUtil.isBlank(jsonString)) {
            return null;
        }
        return getInstance().readValue(jsonString, valueType);
    }

    /**
     * 将json反序列化成对象
     *
     * @param in        InputStream
     * @param valueType class
     * @param <T>       T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable InputStream in, Class<T> valueType) {
        if (in == null) {
            return null;
        }
        return getInstance().readValue(in, valueType);
    }

    /**
     * 将json反序列化成对象
     *
     * @param content       bytes
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable byte[] content, TypeReference<T> typeReference) {
        if (ObjectUtil.isEmpty(content)) {
            return null;
        }
        return getInstance().readValue(content, typeReference);
    }

    /**
     * 将json反序列化成对象
     *
     * @param jsonString    jsonString
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable String jsonString, TypeReference<T> typeReference) {
        if (StrUtil.isBlank(jsonString)) {
            return null;
        }
        return getInstance().readValue(jsonString, typeReference);
    }

    /**
     * 将json反序列化成对象
     *
     * @param in            InputStream
     * @param typeReference 泛型类型
     * @param <T>           T 泛型标记
     * @return Bean
     */
    @SneakyThrows
    @Nullable
    public <T> T readValue(@Nullable InputStream in, TypeReference<T> typeReference) {
        if (in == null) {
            return null;
        }
        return getInstance().readValue(in, typeReference);
    }

    /**
     * 封装 map type
     *
     * @param keyClass   key 类型
     * @param valueClass value 类型
     * @return MapType
     */
    public MapType getMapType(Class<?> keyClass, Class<?> valueClass) {
        return getInstance().getTypeFactory().constructMapType(Map.class, keyClass, valueClass);
    }

    /**
     * 封装 map type
     *
     * @param elementClass 集合值类型
     * @return CollectionLikeType
     */
    public CollectionLikeType getListType(Class<?> elementClass) {
        return getInstance().getTypeFactory().constructCollectionLikeType(List.class, elementClass);
    }

    /**
     * 读取集合
     *
     * @param content      bytes
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    @SneakyThrows
    public <T> List<T> readList(@Nullable byte[] content, Class<T> elementClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        return getInstance().readValue(content, getListType(elementClass));
    }

    /**
     * 读取集合
     *
     * @param content      InputStream
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    @SneakyThrows
    public <T> List<T> readList(@Nullable InputStream content, Class<T> elementClass) {
        if (content == null) {
            return Collections.emptyList();
        }
        return getInstance().readValue(content, getListType(elementClass));
    }

    /**
     * 读取集合
     *
     * @param content      bytes
     * @param elementClass elementClass
     * @param <T>          泛型
     * @return 集合
     */
    @SneakyThrows
    public <T> List<T> readList(@Nullable String content, Class<T> elementClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        return getInstance().readValue(content, getListType(elementClass));
    }

    /**
     * 读取集合
     *
     * @param content    bytes
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    @SneakyThrows
    public <K, V> Map<K, V> readMap(@Nullable byte[] content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        return getInstance().readValue(content, getMapType(keyClass, valueClass));
    }

    /**
     * 读取集合
     *
     * @param content    InputStream
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    @SneakyThrows
    public <K, V> Map<K, V> readMap(@Nullable InputStream content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        return getInstance().readValue(content, getMapType(keyClass, valueClass));
    }

    /**
     * 读取集合
     *
     * @param content    bytes
     * @param keyClass   key类型
     * @param valueClass 值类型
     * @param <K>        泛型
     * @param <V>        泛型
     * @return 集合
     */
    @SneakyThrows
    public <K, V> Map<K, V> readMap(@Nullable String content, Class<?> keyClass, Class<?> valueClass) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyMap();
        }
        return getInstance().readValue(content, getMapType(keyClass, valueClass));
    }

    /**
     * 读取集合
     *
     * @param content bytes
     * @return 集合
     */
    public Map<String, Object> readMap(@Nullable String content) {
        return readMap(content, String.class, Object.class);
    }

    /**
     * 读取集合
     *
     * @param content bytes
     * @return 集合
     */
    @SneakyThrows
    public List<Map<String, Object>> readListMap(@Nullable String content) {
        if (ObjectUtil.isEmpty(content)) {
            return Collections.emptyList();
        }
        return getInstance().readValue(content, new TypeReference<List<Map<String, Object>>>() {
        });
    }

    /**
     * jackson 的类型转换
     *
     * @param fromValue   来源对象
     * @param toValueType 转换的类型
     * @param <T>         泛型标记
     * @return 转换结果
     */
    public <T> T convertValue(Object fromValue, Class<T> toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }

    /**
     * jackson 的类型转换
     *
     * @param fromValue   来源对象
     * @param toValueType 转换的类型
     * @param <T>         泛型标记
     * @return 转换结果
     */
    public <T> T convertValue(Object fromValue, JavaType toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }

    /**
     * jackson 的类型转换
     *
     * @param fromValue      来源对象
     * @param toValueTypeRef 泛型类型
     * @param <T>            泛型标记
     * @return 转换结果
     */
    public <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef) {
        return getInstance().convertValue(fromValue, toValueTypeRef);
    }

    /**
     * tree 转对象
     *
     * @param treeNode  TreeNode
     * @param valueType valueType
     * @param <T>       泛型标记
     * @return 转换结果
     */
    @SneakyThrows
    public <T> T treeToValue(TreeNode treeNode, Class<T> valueType) {
        return getInstance().treeToValue(treeNode, valueType);
    }

    /**
     * 对象转为 json node
     *
     * @param value 对象
     * @return JsonNode
     */
    public JsonNode valueToTree(@Nullable Object value) {
        return getInstance().valueToTree(value);
    }

    /**
     * 判断是否可以序列化
     *
     * @param value 对象
     * @return 是否可以序列化
     */
    public boolean canSerialize(@Nullable Object value) {
        if (value == null) {
            return true;
        }
        return getInstance().canSerialize(value.getClass());
    }

    public Map<String, Object> toMap(String content) {
        try {
            return getInstance().readValue(content, Map.class);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public <T> Map<String, T> toMap(String content, Class<T> valueTypeRef) {
        try {
            Map<String, Map<String, Object>> map = getInstance().readValue(content, new TypeReference<Map<String, Map<String, Object>>>() {
            });
            Map<String, T> result = new HashMap<>(16);
            for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
                result.put(entry.getKey(), toPojo(entry.getValue(), valueTypeRef));
            }
            return result;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public <T> T toPojo(Map fromValue, Class<T> toValueType) {
        return getInstance().convertValue(fromValue, toValueType);
    }

    public ObjectMapper getInstance() {
        return JacksonHolder.INSTANCE;
    }

    private class JacksonHolder {
        private static final ObjectMapper INSTANCE = new JacksonObjectMapper();
    }

    private class JacksonObjectMapper extends ObjectMapper {
        private static final long serialVersionUID = 8179579875588482348L;

        private static final Locale CHINA = Locale.CHINA;

        public JacksonObjectMapper(ObjectMapper src) {
            super(src);
        }

        public JacksonObjectMapper() {
            super();
            //设置地点为中国
            super.setLocale(CHINA);
            //去掉默认的时间戳格式
            super.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            //设置为中国上海时区
            super.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
            //序列化时，日期的统一格式
            super.setDateFormat(new SimpleDateFormat(Constant.PATTERN_DATETIME, CHINA));
            // 单引号
            super.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            // 允许JSON字符串包含非引号控制字符（值小于32的ASCII字符，包含制表符和换行符）
            super.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
            super.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true);
            //失败处理
            super.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            super.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            //单引号处理
            super.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
            //反序列化时，属性不存在的兼容处理s
            super.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            //日期格式化
            super.registerModule(new JavaTimeModule()
                    .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(Constant.DATETIME_FORMAT))
                    .addDeserializer(LocalDate.class, new LocalDateDeserializer(Constant.DATE_FORMAT))
                    .addDeserializer(LocalTime.class, new LocalTimeDeserializer(Constant.TIME_FORMAT))
                    .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(Constant.DATETIME_FORMAT))
                    .addSerializer(LocalDate.class, new LocalDateSerializer(Constant.DATE_FORMAT))
                    .addSerializer(LocalTime.class, new LocalTimeSerializer(Constant.TIME_FORMAT)));
            super.findAndRegisterModules();
        }

        @Override
        public ObjectMapper copy() {
            return new JacksonObjectMapper(this);
        }
    }


}
